#include "pool.h"
#include "helpers.h"
#include <stdlib.h>

namespace HW
{
namespace Memory
{
namespace Pool
{
	void InitPool ( uint8_t* poolRoot , Roster rosterRoot , PoolContainer* poolContainer , uint32_t count )
	{
		size_t poolAlloc = 0;
		size_t rosterAlloc = 0;
		for ( uint8_t i = 0 ; i < count ; ++i )
		{
			if ( !poolContainer[i].isUsed )
				continue;
			poolContainer[i].pool = poolRoot + poolAlloc;
			poolContainer[i].roster = rosterRoot + rosterAlloc;

			poolContainer[i].rosterFreePartition = 0;

			for ( Memory::Pool::RosterElement j = 0 ; j < poolContainer[i].elementCount ; ++j )
			{
				poolContainer[i].roster[j] = j;
			}
			
			poolAlloc += poolContainer[i].elementSize * poolContainer[i].elementCount;
			rosterAlloc += poolContainer[i].elementCount;
		}
	}

	bool CreatePool ( uint8_t* poolRoot , Roster rosterRoot , PoolContainer* poolContainer , uint32_t count )
	{
		size_t poolAlloc = 0;
		size_t rosterAlloc = 0;

		for ( uint8_t i = 0 ; i < count ; ++i )
		{
			if ( !poolContainer[i].isUsed )
				continue;

			poolAlloc += poolContainer[i].elementSize * poolContainer[i].elementCount;
			rosterAlloc += sizeof(RosterElement) * poolContainer[i].elementCount;
		}

		poolRoot = (uint8_t*)malloc ( poolAlloc );
		rosterRoot = (Roster)malloc ( rosterAlloc );

		if ( ( poolRoot == NULL ) || ( rosterRoot == NULL ) )
			return false;
		
		return true;
	}

	RosterElement AllocateFromPool ( PoolContainer& poolContainer )
	{
		if ( poolContainer.rosterFreePartition >= poolContainer.elementCount )
			return poolContainer.elementCount;
		return poolContainer.roster[(poolContainer.rosterFreePartition)++];
	}

	bool DeallocateFromPool ( PoolContainer& poolContainer , const RosterElement id )
	{
		RosterElement idPos = FindElementInRoster ( poolContainer , id );
		if ( idPos >= poolContainer.rosterFreePartition )
			return false;
		poolContainer.rosterFreePartition--;
		Helpers::swap_u32 ( poolContainer.roster[idPos] , poolContainer.roster[poolContainer.rosterFreePartition] );
		return true;
	}

	bool IsAllocated ( const PoolContainer& poolContainer , const RosterElement id )
	{
		if ( FindElementInRoster ( poolContainer , id ) < poolContainer.rosterFreePartition )
				return true;
		return false;
	}

	RosterElement FindElementInRoster ( const PoolContainer& poolContainer , const RosterElement id )
	{
		for ( RosterElement i = 0 ; i < poolContainer.elementCount ; ++i )
			if ( poolContainer.roster[i] == id )
				return i;
		return poolContainer.elementCount;
	}

}
}
}